﻿using MyHome.Configuration.Net;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using ViewModelBase;

namespace MyHome.Configuration.ViewModel
{
    public class PluginHostViewModel : ViewModelBase.ViewModel<ServiceClient>
    {
        public PluginHostViewModel(ServiceClient model)
            : base(model)
        {
        }

        #region LoadPluginsCommand

        private ICommand loadPluginsCommand;

        public ICommand LoadPluginsCommand
        {
            get
            {
                if (loadPluginsCommand == null)
                    loadPluginsCommand = new RelayCommand(async param => await ExecuteLoadPluginsCommand(param));

                return loadPluginsCommand;
            }
        }

        private async Task ExecuteLoadPluginsCommand(object param)
        {
            await Model.LoadPluginsAsync();
        }

        #endregion LoadPluginsCommand

        #region StartPluginsCommand

        private ICommand startPluginsCommand;

        public ICommand StartPluginsCommand
        {
            get
            {
                if (startPluginsCommand == null)
                    startPluginsCommand = new RelayCommand(async param => await ExecuteStartPluginsCommand(param));

                return startPluginsCommand;
            }
        }

        private async Task ExecuteStartPluginsCommand(object param)
        {
            await Model.StartPluginsAsync();
        }

        #endregion StartPluginsCommand

        #region StopPluginsCommand

        private ICommand stopPluginsCommand;

        public ICommand StopPluginsCommand
        {
            get
            {
                if (stopPluginsCommand == null)
                    stopPluginsCommand = new RelayCommand(async param => await ExecuteStopPluginsCommand(param));

                return stopPluginsCommand;
            }
        }

        private async Task ExecuteStopPluginsCommand(object param)
        {
            await Model.StopPluginsAsync();
        }

        #endregion StopPluginsCommand

        #region Plugins property

        private ObservableCollection<PluginViewModel> plugins;

        public ObservableCollection<PluginViewModel> Plugins
        {
            get
            {
                return plugins;
            }
            set
            {
                if (Plugins != value)
                {
                    if (Plugins != null)
                    {
                        Plugins.CollectionChanged -= Plugins_CollectionChanged;
                        foreach (var plugin in Plugins)
                            plugin.PropertyChanged -= plugin_PropertyChanged;
                    }

                    plugins = value;
                    if (Plugins != null)
                    {
                        Plugins.CollectionChanged += Plugins_CollectionChanged;
                        foreach (var plugin in Plugins)
                            plugin.PropertyChanged += plugin_PropertyChanged;
                    }
                    OnPropertyChanged("Plugins");
                }
            }
        }

        private void Plugins_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (PluginViewModel plugin in e.NewItems)
                {
                    plugin.PropertyChanged += plugin_PropertyChanged;
                }
            }
            if (e.OldItems != null)
            {
                foreach (PluginViewModel plugin in e.OldItems)
                {
                    plugin.PropertyChanged -= plugin_PropertyChanged;
                }
            }
        }

        private void plugin_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsSelected")
            {
                var plugin = (PluginViewModel)sender;
                var selected = plugin.IsSelected;
                if (selected)
                {
                    foreach (var p in Plugins)
                    {
                        if (p != plugin)
                            p.IsSelected = false;
                    }
                    foreach (var c in pluginConnections)
                    {
                        c.IsSelected = false;
                    }
                    SelectedPlugin = plugin;
                    SelectedPluginConnection = null;
                }
            }

        }

        #endregion Plugins property

        #region SelectedPlugin property

        private PluginViewModel selectedPlugin;

        public PluginViewModel SelectedPlugin
        {
            get
            {
                return selectedPlugin;
            }
            set
            {
                if (SelectedPlugin != value)
                {
                    selectedPlugin = value;
                    OnPropertyChanged("SelectedPlugin");
                }
            }
        }

        #endregion SelectedPlugin property

        #region PluginConnections property

        private ObservableCollection<PluginConnectionViewModel> pluginConnections;

        public ObservableCollection<PluginConnectionViewModel> PluginConnections
        {
            get
            {
                return pluginConnections;
            }
            set
            {
                if (PluginConnections != value)
                {
                    if (PluginConnections != null)
                    {
                        PluginConnections.CollectionChanged -= PluginConnections_CollectionChanged;
                        foreach (var pluginConnection in PluginConnections)
                            pluginConnection.PropertyChanged -= pluginConnection_PropertyChanged;
                    }
                    pluginConnections = value;
                    if (PluginConnections != null)
                    {
                        PluginConnections.CollectionChanged += PluginConnections_CollectionChanged;
                        foreach (var pluginConnection in PluginConnections)
                            pluginConnection.PropertyChanged += pluginConnection_PropertyChanged;
                    }
                    OnPropertyChanged("PluginConnections");
                }
            }
        }

        async void PluginConnections_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (PluginConnectionViewModel pluginConnection in e.NewItems)
                {
                    pluginConnection.PropertyChanged += pluginConnection_PropertyChanged;
                    //var updatedConnection = await Model.AddPluginConnectionsAsync(pluginConnection.Model);
                    //pluginConnection.Model.Id = updatedConnection.Id;
                }
            }
            if (e.OldItems != null)
            {
                foreach (PluginConnectionViewModel pluginConnection in e.OldItems)
                {
                    pluginConnection.PropertyChanged -= pluginConnection_PropertyChanged;
                    //await Model.DeletePluginConnectionAsync(pluginConnection.Model.Id);
                }
            }
        }
        void pluginConnection_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsSelected")
            {
                var pluginConnection = (PluginConnectionViewModel)sender;
                var selected = pluginConnection.IsSelected;
                if (selected)
                {
                    foreach (var p in Plugins)
                    {
                        p.IsSelected = false;
                    }
                    foreach (var c in pluginConnections)
                    {
                        if (c != pluginConnection)
                            c.IsSelected = false;
                    }
                    SelectedPlugin = null;
                    SelectedPluginConnection = pluginConnection;
                }
            }
        }


        #endregion PluginConnections property

        #region SelectedPluginConnection property

        private PluginConnectionViewModel selectedPluginConnection;

        public PluginConnectionViewModel SelectedPluginConnection
        {
            get
            {
                return selectedPluginConnection;
            }
            set
            {
                if (SelectedPluginConnection != value)
                {
                    selectedPluginConnection = value;
                    OnPropertyChanged("SelectedPluginConnection");
                }
            }
        }

        #endregion SelectedPluginConnection property

        #region UpdateCommand

        private ICommand updateCommand;

        public ICommand UpdateCommand
        {
            get
            {
                if (updateCommand == null)
                    updateCommand = new RelayCommand(async param => await ExecuteGetPluginsCommand(param));

                return updateCommand;
            }
        }

        private async Task ExecuteGetPluginsCommand(object param)
        {
            Plugins = new ObservableCollection<PluginViewModel>((await Model.GetPluginsAsync()).Select(t => new PluginViewModel(t, this)));
            PluginConnections = new ObservableCollection<PluginConnectionViewModel>((await Model.GetPluginConnectionsAsync()).Select(t => new PluginConnectionViewModel(t, this)));

            var types = await Model.GetPluginTypesAsync();
            PluginTypes = new ObservableCollection<string>(types);
        }

        #endregion UpdateCommand

        #region SavePluginsCommand

        private ICommand savePluginsCommand;

        public ICommand SavePluginsCommand
        {
            get
            {
                if (savePluginsCommand == null)
                    savePluginsCommand = new RelayCommand(async param => await ExecuteSavePluginsCommand(param));

                return savePluginsCommand;
            }
        }

        private async Task ExecuteSavePluginsCommand(object param)
        {
            var updatedPlugins = await Model.UpdatePluginsAsync(Plugins.Select(p => p.Model).ToList());
            var updatedConnections = await Model.UpdatePluginConnectionsAsync(PluginConnections.Select(c => c.Model).ToList());
            Plugins = new ObservableCollection<PluginViewModel>(updatedPlugins.Select(t => new PluginViewModel(t, this)));
            PluginConnections = new ObservableCollection<PluginConnectionViewModel>(updatedConnections.Select(t => new PluginConnectionViewModel(t, this)));

        }

        #endregion SavePluginsCommand

        #region PluginTypes property

        private ObservableCollection<string> pluginTypes;

        public ObservableCollection<string> PluginTypes
        {
            get
            {
                return pluginTypes;
            }
            set
            {
                if (PluginTypes != value)
                {
                    pluginTypes = value;
                    OnPropertyChanged("PluginTypes");
                }
            }
        }

        #endregion PluginTypes property

        #region SelectedPluginType property

        private string selectedPluginType;

        public string SelectedPluginType
        {
            get
            {
                return selectedPluginType;
            }
            set
            {
                if (SelectedPluginType != value)
                {
                    selectedPluginType = value;
                    OnPropertyChanged("SelectedPluginType");
                }
            }
        }

        #endregion SelectedPluginType property

        #region AddCommand

        private ICommand addCommand;

        public ICommand AddCommand
        {
            get
            {
                if (addCommand == null)
                    addCommand = new RelayCommand(async param => await ExecuteAddCommand(param));

                return addCommand;
            }
        }

        private async Task ExecuteAddCommand(object param)
        {
            var template = new PluginTemplate { PluginType = SelectedPluginType };
            var updated = await Model.AddPluginAsync(template);
            Plugins.Add(new PluginViewModel(updated, this));
        }

        #endregion AddCommand

        protected override void Initialize()
        {
            // Plugins = await Model.GetPluginsAsync();
            base.Initialize();
        }

        ~PluginHostViewModel()
        {
            Model.Close();
        }
    }
}